/*
 * InicializacionBD.java
 * 0.2 31/10/2012
 *
 * Authors: José Luis Urbano Orgaz (joseluislikebetter@hotmail.com)
 *          Milagros Membrillo Jimenez
 *
 * Copyright: This file is part of E-Man.
 *   
 *   E-Man is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *  
 *   E-Man is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU General Public License for more details.
 *  
 *   You should have received a copy of the GNU General Public License
 *   along with E-Man.  If not, see <http://www.gnu.org/licenses/>.
 */
package inicializacionbd;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author Milagros Membrillo Jimenez
 * @author José Luis Urbano Orgaz
 */
public class InicializacionBD {

    private Connection con;
    private Statement st;
    private ResultSet rs;

    /**
     * Busca un apellido aleatorio en la tabla de apellidos
     * @return apellido aleatorio
     */
    private String ObtenerApellido() {
        String sentencia;
        String apellido = "";
        int idAleatorio = (int) (Math.random() * 1386 + 1); //Calcula un número aleatorio entre 1 y 1386
        sentencia = "select Apellido from tapellidos where id=".concat(String.valueOf(idAleatorio));
        try {
            EjecutarConsulta(sentencia); //Busca el apellido con id el número aleatorio
            rs.first();
            apellido = rs.getString("Apellido"); //y lo asigna a una variable
        } catch (SQLException ex) {
            System.out.print("Fallo al buscar apellido en la Base de Datos");
            ex.printStackTrace();
        }
        return apellido;
    }

     /**
     * Busca un nombre aleatorio en la tabla de nombres
     * @return nombre aleatorio
     */
    private String ObtenerNombre() {
        String sentencia;
        String nombre = "";
        int idAleatorio = (int) (Math.random() * 187 + 1); //Calcula un número aleatorio entre 1 y 187
        sentencia = "select Nombre from tnombre where id=".concat(String.valueOf(idAleatorio));
        try {
            EjecutarConsulta(sentencia);//Busca el nombre con id el número aleatorio
            rs.first();
            nombre = rs.getString("Nombre"); //y lo asigna a una variable
        } catch (SQLException ex) {
            System.out.print("Fallo al buscar nombre en la Base de Datos");
            ex.printStackTrace();
        }
        return nombre;
    }

    /**
     * Escoge 3 provincias aleatorias con posibilidades de tener clientes
     * @return array de enteros con los ID de provincias
     */
    private int[] ElegirProvincias() {
        int[] provinciasElegidas = new int[3]; //Array de provincias
        int contador = 0; //Contador de provincias ya seleccionadas
        String sentencia; //Sentencia SQL a ejecutar
        int idAleatorio; //ID de provincia aleatorio
        boolean repetido; //Comprueba que si se ha repetido o no la provincia
        int numTotalPoblaciones = 0; //Cuenta la suma total de poblaciones entre todas las provincias
        boolean hayCallesenProvincia;
        int numPobl;
        while (numTotalPoblaciones < 9) { 
            //Mientras el número total de poblaciones sea inferior a 9 se repetirá el proceso
            while (contador < 3) { //<repite la búsqueda 3 veces (3 provincias)
                idAleatorio = (int) (Math.random() * 50 + 1); //Calcula un id de provincia aleatorio entre 1 y 50
                repetido = false; 
                for (int i = 0; i < provinciasElegidas.length; i++) //Buscamos provincia a provincia
                {
                    if (provinciasElegidas[i] == idAleatorio) //Por si se ha repetido
                    {
                        repetido = true;
                    }
                }
                if (!repetido) //En caso de estar repetido, se vuelve a buscar otra provincia, si no, continúa
                {
                sentencia = "select count(*), CodigoPoblacion from poblaciones where CodigoProvincia=".concat(String.valueOf(idAleatorio));
                try {
                    EjecutarConsulta(sentencia); //Contamos el número de poblaciones  y su código
                    rs.first();
                    numPobl=rs.getInt(1);
                    numTotalPoblaciones+=numPobl;
                    if (numPobl != 0) //Comprueba si tiene alguna población
                    {
                        sentencia = "select count(*) from callespoblaciones where CodPoblacion=".concat(rs.getString(2));
                        EjecutarConsulta(sentencia);//En caso de tener alguna población, cuenta sus calles
                        rs.first();
                        if (Integer.parseInt(rs.getString(1)) != 0) //Coprueba  que tenga alguna
                        {
                            provinciasElegidas[contador] = idAleatorio; //La provincia es válida y se añade
                            contador++; //El contador de provincias se incrementa
                        }
                    }

                } catch (SQLException ex) {
                    System.out.print("Fallo al seleccionar provincia en la Base de Datos");
                    ex.printStackTrace();
                }
                }
            }
            //Se realiza una comprobación extra que podría reiniciar todo el proceso de selección:
            //se especifica que el número de poblaciones debe ser 9, por lo que se comprueba que
            //la suma de las poblaciones de las provincias seleccionadas sea superior
            if (numTotalPoblaciones < 9)
            {
                contador = 0;
                for (int i = 0; i < provinciasElegidas.length; i++)
                { //Reinicialización de los datos
                    provinciasElegidas[i] = 0;
                }
            }
        }
        return provinciasElegidas;
    }
    
    /**
     * Permite obtener el código de una provincia dada una población
     * @param poblacion ID de la población de la que se quiere conocer la provincia
     * @return Código ID de la provincia
     */
    private int ObtieneProvincia(int poblacion) {
        int codProvincia= 0;
        String sentencia;
            sentencia = "select CodigoProvincia from poblaciones where CodigoPoblacion=".concat(String.valueOf(poblacion));
            try {
                EjecutarConsulta(sentencia); //Busca el ID de la provincia dado el ID de la población
                rs.first();
                codProvincia=rs.getInt(1);
            } catch (SQLException ex) {
                System.out.println("Fallo al obtener la provincia dada la localidad");
                ex.printStackTrace();
            }
        return codProvincia;
    }

    /**
     * Permite obtener poblaciones aleatorias en las provincias seleccionadas
     * @param provincias Array de IDs con las provincias seleccionadas
     * @return Array de IDs con las poblaciones seleccionadas
     */
    private int[] ObtenerPoblaciones(int[] provincias) {
        String sentencia;
        int[] poblaciones = new int[9]; //El límite de poblaciones está establecido en 9
        boolean[] provUsadas = {false, false, false}; //Las 3 provincias se deben usar
        int posicionFalse; //Iterador que comprueba si se han utilizado las 3 provincias
        int numPoblaciones = 0; //Contador que cuenta las poblaciones seleccionadas
        int prov; //Indicador de cual es la provincia elegida
        int pobAleat; //Indica el código relativo de una población (en una provincia)
        int iter = 0; //Iterador que permite recorrer el array de poblaciones
        int poblacion; //Código de la población (poblacion=codprovincia*1000+pobAleat)
        boolean compruebaCalles; //Comprueba si hay calles en la población
        boolean salidaBucle; //Termina el bucle: hay una provincia sin elegir población
        while (numPoblaciones < 9) //Recorre las 9 poblaciones
        {
            salidaBucle = false;
            posicionFalse = -1;
            //Compobamos si hay alguna provincia que no tenga ninguna población escogida
            for (int i = provUsadas.length - 1; (i >= 0) && (salidaBucle == false); i--) 
            {
                if (!provUsadas[i]) 
                {
                    posicionFalse = i;
                    provUsadas[i] = true;
                    salidaBucle = true;
                }
            }
            //En caso de que las 3 provincias tengan alguna población elegida
            if (posicionFalse == -1) 
            {
                prov = (int) (Math.random() * 3); //La elegimos aleatoriamente
            } 
            else //En caso de haber alguna provincia sin población escogida
            {
                prov = posicionFalse; //La elegiremos
            }
            //Contaremos el número de poblaciones de la provincia seleccionada
            sentencia = "select count(*) from poblaciones where CodigoProvincia=".concat(String.valueOf(provincias[prov]));
            try {
                EjecutarConsulta(sentencia);
                rs.first();
                //Y seleccionaremos una de forma aleatoria con respecto a su provincia
                pobAleat = (int) ((Math.random() * rs.getInt(1)) + 1);
                //Y obtendremos su código de población
                poblacion = (provincias[prov] * 1000) + pobAleat;
                //Comprobaremos que haya calles en la población
                compruebaCalles = CompruebaCallesenPoblacion(poblacion);
                if (compruebaCalles) //en cuyo caso la añadiremos al array 
                {
                    poblaciones[iter] = poblacion;
                    iter++;             //y actualizaremos las variables
                    numPoblaciones++;
                }
            } catch (SQLException ex) {
                System.out.println("Fallo en la selección de las poblaciones");
                // Logger.getLogger(InicializacionBD.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        return poblaciones;
    }

    /**
     * Comprueba si hay o no calles en una población
     * @param poblacion Código de la población
     * @return si hay calles (true) o no (false)
     */
    private boolean CompruebaCallesenPoblacion(int poblacion) {
        boolean hayCalles = false;
        String sentencia = "select count(*) from callespoblaciones where CodPoblacion=".concat(String.valueOf(poblacion));
        try {
            EjecutarConsulta(sentencia);
            rs.first();
            //En caso de haber alguna calle en la población
            if (rs.getInt(1) > 0) {
                hayCalles = true;
            }
        } catch (SQLException ex) {
            System.out.println("Fallo en la comprobación de calles en la población");
            // Logger.getLogger(InicializacionBD.class.getName()).log(Level.SEVERE, null, ex);
        }
        return hayCalles;
    }
    
    private int getCalleAleatoria(int poblacion) {
        int contaCalles=0;
        int idCalle=0;
        String sentencia = "select count(*),idCalle from callespoblaciones where CodPoblacion=".concat(String.valueOf(poblacion));
        try {
            EjecutarConsulta(sentencia);
            rs.first();
            contaCalles=(int) (Math.random() * rs.getInt(1)+1);
            while(contaCalles!=0)
            {
                idCalle=rs.getInt(2);
                rs.next();
                contaCalles--;
            }
        } catch (SQLException ex) {
            System.out.println("Fallo en la obtención de la calle aleatoria");
        }
        return idCalle;
    }
    
    private String[] ObtenerNumeroPisoMetro()
    {
        String[] valores=new String[3];
        valores[0] = String.valueOf((int)(Math.random() * 99 + 1));
        valores[1] = String.valueOf((int)(Math.random() * 99 + 1));
        valores[2] = String.valueOf((int)(Math.random() * 99));
        return valores;
    }

    private void InsertarCliente(String nombre, String apellido1,
            String apellido2, int provincia, int poblacion, int calle, String[] NPM)
    {
        
       String sentencia = "INSERT INTO clientes VALUES(NULL,'"+nombre+"','"+apellido1+"','"+apellido2+"',"+calle+","+NPM[0]+","+NPM[1]+","+NPM[2]+",'"+String.valueOf(poblacion)+"',"+String.valueOf(provincia)+");";
       System.out.println(sentencia);
        try {
            st.executeUpdate(sentencia);
        }catch(SQLException ex) {
            System.out.println("Fallo en la inserción de clientes");
            // Logger.getLogger(InicializacionBD.class.getName()).log(Level.SEVERE, null, ex);
        }
       
    }
    
    private int DiaAleatorio(int anho, int mes)
    {
        int diaAleatorio=0;
        //int mes = (int) (12 * Math.random()+1);
        if (mes == 2) {//Mes de febrero
            if (anho % 400 == 0 || anho % 4 == 0) {//es bisiesto
                diaAleatorio = (int) (29 * Math.random()+1);
            } else {//No es año bisiesto
                diaAleatorio = (int) (28 * Math.random()+1);
            }
        } else {
            if ((mes == 1) || (mes == 3) || (mes == 5) || (mes == 7) || (mes == 8) || (mes == 10) || (mes == 12)) {
                //Mes de 31 días
                diaAleatorio = (int) (31 * Math.random()+1);
            } else {//Mes de 30 días
                diaAleatorio = (int) (Math.random()*30+1);
            }
        }
            return diaAleatorio;
    }
    
    private String TimeAleatorio()
    {
        String time="";
        int hora = (int) (Math.random() * 24);
        if (hora<10)
            time="0";
        time=time.concat(String.valueOf(hora)+":");
        int min = (int) (Math.random() * 60);
        if (min<10)
            time=time.concat("0");
        time=time.concat(String.valueOf(min)+":");
        int seg = (int) (Math.random() * 60);
        if (seg<10)
            time=time.concat("0");
        time=time.concat(String.valueOf(seg));
        return time;
    }
    
    private synchronized void InsertarMedidasaTodoslosClientes()
    {
        ArrayList<Integer> listaClientes=new ArrayList<Integer>();
        String sentencia = "select * from clientes;";
        Iterator itr;
        int mes=1;
        int dia=0;
        int anho=2012;
        int cliente;
        String fecha="";
        double medicion;
        try {
            EjecutarConsulta(sentencia);
            while(rs.next())
            {
                listaClientes.add(rs.getInt(1));
            }
             itr= listaClientes.iterator();
            while (itr.hasNext())
            {
                cliente=(int)itr.next();
                for (int i=1;i<6;i++)
                {
                    dia=DiaAleatorio(anho,i);
                    fecha=String.valueOf(anho)+"-0"+i+"-"+String.valueOf(dia)+" "+TimeAleatorio();
                    medicion = Math.random() * 1200;
                    InsertarMedicion(cliente, fecha, medicion);
                }
            }
        } catch (SQLException ex) {
            System.out.println("Fallo en la ejecución de la instrucción vayaaaaaa");
            // Logger.getLogger(InicializacionBD.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private synchronized void InsertarMedicion(int cliente, String fecha, double medicion)
    {
       DecimalFormat formateador = new DecimalFormat("##################.00");
       DecimalFormatSymbols simb=new DecimalFormatSymbols();
       simb.setDecimalSeparator('.');
       formateador.setDecimalFormatSymbols(simb);
       String sentencia = "INSERT INTO mediciones VALUES(NULL,'"+cliente+"','"+fecha+"','"+formateador.format(medicion) +"');";
       System.out.println(sentencia);
        try {
            st.executeUpdate(sentencia);
        }catch(SQLException ex) {
            System.out.println("Fallo en la ejecución de la instrucción aqui?");
            // Logger.getLogger(InicializacionBD.class.getName()).log(Level.SEVERE, null, ex);
        }
       
    }
    
    /**
     * Prepara el código java para lanzar sentencias
     *
     * @throws SQLException Lanza excepción en lugar de capturarla
     */
    public void PrepararSentencia() throws SQLException {
        st = con.createStatement();
    }

    /**
     * Establece la conexión con la BD
     *
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void abrirConexion() throws InstantiationException, IllegalAccessException {

        try {
            String userName = "Invitado";
            String password = "liker";

            String url = "jdbc:mysql://127.0.0.1/consumoelectrico";

            Class.forName("com.mysql.jdbc.Driver").newInstance();
            con = DriverManager.getConnection(url, userName, password);

            System.out.println("Conexion a la BD");

        } catch (ClassNotFoundException e) {
            // Error. No se ha encontrado el driver de la BD
            // e.printStackTrace();
            System.out.println("vaya chaco");
        } catch (SQLException e) {
            // Error. No se ha podido conectar a la BD
            //e.printStackTrace();
        }
    }

    /**
     * Ejecuta cada consulta, recibiendo el nombre de la consulta a devolver
     *
     * @param consulta
     * @throws SQLException
     */
    public void EjecutarConsulta(String consulta) throws SQLException {
        rs = st.executeQuery(consulta);
    }

    /**
     * Cierra la conexión con la BD
     */
    public void cerrarConexion() {
        try {
            con.close();
            System.out.println("Conexion cerrada");
        } catch (SQLException e) {
            // System.out.println("Error al cerrar conexion");
        }
    }

    public static void main(String[] args) {
        InicializacionBD c = new InicializacionBD();
        String nombre;
        String apellido1;
        String apellido2;
        int[] provinciasElegidas;
        int[] poblacionesElegidas;
        int calle=0;
        int valorAleatorio;
        boolean salidaBucle;
        int posicionFalse;
        boolean[] poblacionUsada=new boolean[9];
        int provUsada;
        for(int i=0;i<poblacionUsada.length;i++)
        {
            poblacionUsada[i]=false;
        }
        String[] NumPsMtr;
        try {
            c.abrirConexion();//Solo se realiza una vez
            c.PrepararSentencia();//Solo se realiza una vez
            provinciasElegidas = c.ElegirProvincias();
            poblacionesElegidas = c.ObtenerPoblaciones(provinciasElegidas);
           for(int j=0;j<20000;j++)
           {
            System.out.print(j+": ");
            nombre = c.ObtenerNombre();
            apellido1 = c.ObtenerApellido();
            apellido2 = c.ObtenerApellido();
            NumPsMtr=c.ObtenerNumeroPisoMetro();
            salidaBucle = false;
            posicionFalse = -1;
            for (int i = poblacionesElegidas.length - 1; (i >= 0) && (salidaBucle == false); i--) {
                if (!poblacionUsada[i]) {
                    posicionFalse = i;
                    poblacionUsada[i] = true;
                    salidaBucle = true;
                }
            }
            if (posicionFalse == -1) {
                valorAleatorio = (int) (Math.random() * 9);
            } else {
                valorAleatorio = posicionFalse;
            }
            calle=c.getCalleAleatoria(poblacionesElegidas[valorAleatorio]);
            provUsada=c.ObtieneProvincia(poblacionesElegidas[valorAleatorio]);
           c.InsertarCliente(nombre, apellido1, apellido2, provUsada, poblacionesElegidas[valorAleatorio], c.getCalleAleatoria(poblacionesElegidas[valorAleatorio]), NumPsMtr);
           } 
           
        } catch (Exception e) {
            System.out.println("Se ha producido una excepción en el acceso a la Base de Datos");
        }
        
        
        double f=276963.9832;
        
      c.InsertarMedidasaTodoslosClientes();
      c.cerrarConexion();//Solo se realiza una vez
    }

    }
